structure MipsFrame : FRAME =
struct
    structure E = ErrorMsg
    structure M = Temp
    structure R = Tree

    type register = string    

    datatype access = InFrame of int
		    | InReg of M.temp

    (*
     * The first 4 parameters are passed in registers, with remaining ones passed on the stack
     *
     * The stack layout is
     *
     *  outgoing args                                 incoming args    older frames ...
     *                 temps | ret | locals | static parm ... parm | ...
     *               ^                      ^ 
     *              SP                     FP
     *  ... lower addresses ...................................... higher addresses ...
     *)


    type frame = {label : M.label, formals:  access list, localrefs : access list ref}
     
    val wordSize = 4

    val FP = M.newtemp();
    val SP = M.newtemp();
    val RV = M.newtemp();
    val RA = M.newtemp();
    val R4= M.newtemp(); (*incoming argument 1*)
    val R5= M.newtemp(); (*argument 2*)
    val R6= M.newtemp(); (*argument 3*)
    val R7= M.newtemp(); (*argument 4*)

    (*TODO inclomplete*)
    val tempMap = List.foldl (fn ((k, v), t) => Temp.Table.enter(t, k, v))
			     Temp.Table.empty
			     [(FP,"r29"),
			      (RA,"r31"),
			      (SP,"r30"),
		              (RV,"r2"),
			      (R4,"r4"),
			      (R5,"r5"),
			      (R6,"r6"),
			      (R7,"r7") ]
		   
    (* formals will be a list of k booleans, where true for each parameter that escaps or false for each parameters that does not *)
    fun newFrame {name, formals} : frame =
    	let
      
    
    (*Function frmls has 3 parameters formals, location- location in memory, reg- register for formals that don't escape*)
           val formalss =(let fun frmls nil location reg =[]						  
		      			  | frmls (head::rest) location reg =( if head then  InFrame(location) :: frmls (rest) (location+wordSize)reg
						    	  	       	      else (case reg of
									      4 => InReg(R4):: frmls rest location (reg+1)
									      |5=> InReg(R5):: frmls rest location (reg+1)
									      |7=> InReg(R6):: frmls rest location (reg+1)
									      |8=> InReg(R7):: frmls rest location (reg+1)
									      |_ => InFrame (location) :: frmls (rest) (location+wordSize)reg (*no more registers*)
									      )
									   )
					     in frmls formals 0 4 
					     end)
	in
		{label = name, formals =formalss, localrefs = ref []}  
	end


    fun name {label=label, formals=formals, localrefs=localrefs} = label
    fun formals {label=label, formals=formals, localrefs=localrefs} = formals
			
    fun allocLocal {label=label, formals=formals, localrefs=localrefs} true  = let
    		   		 val lastaccess = case !localrefs of [] => InFrame 0
					| locallist => List.last(locallist) 
				 val InFrame lastpos = lastaccess
	      			 val nextaccess =InFrame ( lastpos - wordSize)
	
				in 
				   localrefs := (! localrefs) @ [nextaccess];
				   nextaccess
				end

      | allocLocal {label=label, formals=formals, localrefs=localrefs} false = InReg(M.newtemp())

      fun procEntryExit1 (frame, body)=body
      
      fun externalCall (s,args) = R.CALL (R.NAME (M.namedlabel s), args)


      fun exp(InFrame(i)) =  (fn (fp) =>
	           R.MEM(R.BINOP(R.PLUS, fp, R.CONST(i))))



(*    val registers : register list

    val RV = Temp.newtemp ()
    val FP = Temp.newtemp ()


    val tempMap : register Temp.Table.table

    val externalCall : string * Tree.exp list -> Tree.exp

    val string : Temp.label * string -> string

    val procEntryExit1 : frame * Tree.stm -> Tree.stm
    val procEntryExit2 : frame * Assem.instr list -> Assem.instr list
    val procEntryExit3 : frame * Assem.instr list -> {prolog : string, body : Assem.instr list, epilog : string}
*)

    datatype frag = PROC of {body : Tree.stm, frame : frame}
		  | STRING of Temp.label * string
end
